#include <iostream>
#include <string>
#include <sstream>
#include <random>
#include <google/protobuf/map.h>
#include "httplib.h"
#include "add_contact.pb.h"

using namespace httplib;

class ContactsException
{
public:
    ContactsException(const std::string &str = "A problem") : message(str) {}
    ~ContactsException() {}

    std::string what() const
    {
        return message;
    }

private:
    std::string message;
};

void printContact(add_contact::AddContactRequest &req)
{
    std::cout << "联系人姓名：" << req.name() << std::endl;
    std::cout << "联系人年龄: " << req.age() << std::endl;
    for (int j = 0; j < req.phone_size(); j++)
    {
        const add_contact::AddContactRequest_Phone &phone = req.phone(j);
        std::cout << "联系人电话: " << j + 1 << " " << phone.number();

        std::cout << "  (" << phone.PhoneType_Name(phone.type()) << ")" << std::endl;
    }
}

class Utils
{
public:
    static unsigned int random_char()
    {
        // ⽤于随机数引擎获得随机种⼦
        std::random_device rd;
        // mt19937是c++11新特性，它是⼀种随机数算法，⽤法与rand()函数类似，但是mt19937 具有速度快，周期⻓的特点
        // 作⽤是⽣成伪随机数
        std::mt19937 gen(rd());
        // 随机⽣成⼀个整数i 范围[0, 255]
        std::uniform_int_distribution<> dis(0, 255);
        return dis(gen);
    }
    // ⽣成 UUID （通⽤唯⼀标识符）
    static std::string generate_hex(const unsigned int len)
    {
        std::stringstream ss;
        // ⽣成 len 个16进制随机数，将其拼接⽽成
        for (auto i = 0; i < len; i++)
        {
            const auto rc = random_char();
            std::stringstream hexstream;
            hexstream << std::hex << rc;
            auto hex = hexstream.str();
            ss << (hex.length() < 2 ? '0' + hex : hex);
        }
        return ss.str();
    }
    static void map_copy(google::protobuf::Map<std::string, std::string> *target, const google::protobuf::Map<std::string, std::string> &source)
    {
        if (nullptr == target)
        {
            std::cout << "map_copy warning, target is nullptr!" << std::endl;
            return;
        }
        for (auto it = source.cbegin(); it != source.cend(); ++it)
        {
            target->insert({it->first, it->second});
        }
    }
};

int main()
{
    std::cout << "-------------服务启动-------------" << std::endl;
    Server server;

    server.Post("/contacts/add", [](const Request &req, Response &resp) {
        std::cout << "接收到post请求!" << std::endl;
        // 反序列化 request req.body
        add_contact::AddContactRequest request;
        add_contact::AddContactResponse response;
        try {
            if(!request.ParseFromString(req.body)) {
                throw ContactsException("AddContactRequest 反序列化失败! ");
            }
    
            // 新增联系人，持久化存储通讯录  ----> 打印新增的联系人信息
            printContact(request);
    
            // 构造 response resp.body
            response.set_success(true);
            response.set_uid(Utils::generate_hex(10));
    
            // resp.body（序列化 response）
            std::string response_str;
            if(!response.SerializeToString(&response_str)) {
                throw ContactsException("AddContactResponse 序列化失败");
            }
            resp.status = 200;
            resp.body = response_str;
            resp.set_header("Content-Type", "application/protobuf");
        } catch (const ContactsException &e) {
            resp.status = 500;
            response.set_success(false);
            response.set_error_desc(e.what());
            std::string response_str;
            if(response.SerializeToString(&response_str)) {
                resp.body = response_str;
                resp.set_header("Content-Type", "application/protobuf");
            }
            std::cout << "/contacts/add 发生异常，异常信息：" << e.what() << std::endl;
        } 
    });

    // 绑定 8080 端口，并且将端口对外开放
    server.listen("0.0.0.0", 8080);

    return 0;
}

// int main()
// {
//     std::cout << "-------------服务启动-------------" << std::endl;
//     Server server;

//     server.Post("/test-post", [](const Request &req, Response &resp) {
//         std::cout << "接收到post请求!" << std::endl;
//         resp.status = 200;
//     });

//     server.Get("/test-get", [](const Request &req, Response &resp) {
//         std::cout << "接收到get请求!" << std::endl;
//         resp.status = 200;
//     });

//     // 绑定 8080 端口，并且将端口对外开放
//     server.listen("0.0.0.0", 8080);

//     return 0;
// }